package com.bite.friend.manager;


import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bit.common.redis.service.RedisService;
import com.bite.common.core.constants.CacheConstants;
import com.bite.common.core.domain.BaseEntity;
import com.bite.common.core.enums.ResultCode;
import com.bite.common.security.exception.ServiceException;
import com.bite.friend.domain.exam.ExamQuestion;
import com.bite.friend.domain.question.Question;
import com.bite.friend.domain.question.vo.QuestionVO;
import com.bite.friend.mapper.exam.ExamQuestionMapper;
import com.bite.friend.mapper.question.QuestionMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;


@Component
public class QuestionCacheManager {

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private ExamQuestionMapper examQuestionMapper;

    public Long getExamFirstQuestion(Long examId) {
        String questionListKey = getQuestionListKey(examId);
        Long index = redisService.index(questionListKey, 0L, Long.class);
        if (index == null || index == -1) {
            refreshCache(examId);
        }
        return redisService.index(questionListKey, 0L, Long.class);
    }


    public Long preQuestion(Long questionId) {
        return preQuestion(questionId, null);
    }

    public Long preQuestion(Long questionId, Long examId) {
        Long index = getIndex(questionId, examId);
        if (index <= 0) {
            throw new ServiceException(ResultCode.FIRST_QUESTION);
        }
        return redisService.index(getQuestionListKey(examId), index - 1, Long.class);
    }

    public Long nextQuestion(Long questionId) {
        return nextQuestion(questionId, null);
    }

    public Long nextQuestion(Long questionId, Long examId) {
        Long index = getIndex(questionId, examId);
        String cacheKey = getQuestionListKey(examId);
        Long listSize = getListSize(examId);
        if (index >= listSize - 1) {
            throw new ServiceException(ResultCode.LAST_QUESTION);
        }
        return redisService.index(cacheKey, index + 1, Long.class);
    }

    public Long getListAllSize() {
        return getListSize(null);
    }

    public Long getHotListSize() {
        return redisService.getListSize(getHotListKey());
    }

    /**
     * examId 为null 就获取全部
     * @param examId
     * @return
     */
    public Long getListSize(Long examId) {
        return redisService.getListSize(getQuestionListKey(examId));
    }

    /**
     * 删除QuestionList 中的Id
     * @param questionId
     * @return
     */
    public Long delIdFromQuestionList(Long questionId) {
        return redisService.removeForList(getQuestionListKey(null), questionId);
    }



    public List<QuestionVO> getHostList() {
        List<Long> questionIdList = redisService.getCacheListByRange(getHotListKey(), 0, -1, Long.class);
        List<String> keyList = questionIdList.stream().map(this::getQuestionHotVOKey).toList();
        return redisService.multiGet(keyList, QuestionVO.class);
    }

    public void refreshAllCache() {
        refreshCache(null);
    }

    /**
     * 刷新竞赛的题目 examId 为null的时候就刷新所有题目 不为null 就刷新竞赛的题目
     * @param examId
     */
    public void refreshCache(Long examId) {
        List<Long> questionIds = null;
        if (examId == null) {
            // 获取所有题目Id
            questionIds = questionMapper.selectList(new LambdaQueryWrapper<Question>().select(Question::getQuestionId).orderByDesc(BaseEntity::getCreateTime))
                    .stream().map(Question::getQuestionId).toList();
        } else {
            // 获取竞赛中题目Id
            questionIds = examQuestionMapper.selectList(new LambdaQueryWrapper<ExamQuestion>()
                    .select(ExamQuestion::getQuestionId)
                    .eq(ExamQuestion::getExamId, examId)
                    .orderByAsc(ExamQuestion::getQuestionOrder)
                ).stream().map(ExamQuestion::getQuestionId).toList();
        }
        if (CollectionUtil.isEmpty(questionIds)) return;
        String questionListKey = getQuestionListKey(examId);
        redisService.rightPushAll(questionListKey, questionIds);
        if (examId != null) {
            long second = ChronoUnit.SECONDS.between(LocalDateTime.now(),
                    LocalDateTime.now().plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0));
            redisService.expire(questionListKey, second);
        }
    }


    public void refreshHotListCache() {
        Set<Long> questionIdList = questionMapper.selectList(new LambdaQueryWrapper<>(Question.class)
                        .select(Question::getQuestionId)
                        .orderByDesc(Question::getQuestionHot))
                .stream().map(Question::getQuestionId).collect(Collectors.toSet());
        if (CollectionUtil.isEmpty(questionIdList)) return;
        String hotListKey = getHotListKey();
        redisService.rightPushAll(hotListKey, questionIdList);
    }

    private Long getIndex(Long questionId, Long examId) {
        String cacheKey = getQuestionListKey(examId);
        Long listSize = redisService.getListSize(cacheKey);
        if (listSize == null || listSize <= 0) {
            refreshCache(examId);
        }
        Long index = redisService.indexOf(cacheKey, questionId);
        if (index == null) {
            // 刚好用户浏览的时候删除这一道题目
            throw new ServiceException(ResultCode.QUESTION_NOT_EXIST);
        }
        return index;
    }

    /**
     * 有竞赛那么就获取竞赛中题目列表的key 没有的话就获取所有的题目列表的key
     * @param examId
     * @return
     */
    private String getQuestionListKey(Long examId) {
        return examId == null ? CacheConstants.QUESTION_LIST : CacheConstants.EXAM_QUESTION_LIST + examId;
    }

    private String getQuestionHotVOKey(Long questionId) {
        return CacheConstants.QUESTION_HOT_DETAIL + questionId;
    }

    private String getHotListKey() {
        return CacheConstants.QUESTION_HOT_LIST;
    }


}
